import hashlib
import sys
import traceback

import mysql.connector
from mysql.connector import Error
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QLabel,
                             QLineEdit, QPushButton, QMessageBox, QHBoxLayout,
                             QDialog, QGroupBox, QFormLayout)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont


class BankCardManager:
    """银行卡管理系统（包含登录和密码修改功能）"""
    def __init__(self):
        print("数据库连接初始化")
        try:
            # 数据库连接配置
            self.connection = mysql.connector.connect(
                host='localhost',
                database='bank system',
                user='root',
                password='1234',
                autocommit=True
            )
            if self.connection.is_connected():
                db_info = self.connection.server_info
                print(f"成功连接到MySQL服务器 (版本 {db_info})")
        except Error as e:
            print(f"数据库连接失败: {e}")
            raise RuntimeError(f"无法连接数据库: {str(e)}")

    def login(self, card_id, password):
        """验证银行卡登录"""
        try:
            cleaned_card_id = card_id.replace(" ", "")

            # 验证卡号格式
            if len(cleaned_card_id) != 16 or not cleaned_card_id.isdigit():
                return False, "卡号长度必须为16位数字"

            # 验证密码格式
            if len(password) != 6 or not password.isdigit():
                return False, "密码必须为6位数字"

            # 查询数据库
            cursor = self.connection.cursor(dictionary=True)
            query = """
            SELECT cardID, customerID, balance, IsReportLoss 
            FROM cardInfo 
            WHERE cardID = %s AND pass = %s
            """
            cursor.execute(query, (cleaned_card_id, password))
            result = cursor.fetchone()
            cursor.close()

            if result:
                # 检查卡是否挂失
                if result['IsReportLoss'] == '是':
                    return False, "该卡已挂失，无法登录"
                return True, result
            return False, "卡号或密码错误"
        except Error as e:
            print(f"数据库查询失败: {e}")
            return False, f"数据库错误: {str(e)}"

    def change_password(self, card_id, old_pass, new_pass):
        """修改银行卡密码（适应明文存储的数据库）"""
        cursor = None
        try:
            # 验证密码格式
            if len(old_pass) != 6 or not old_pass.isdigit():
                return False, "原密码必须为6位数字"
            if len(new_pass) != 6 or not new_pass.isdigit():
                return False, "新密码必须为6位数字"

            # 检查新旧密码是否相同
            if old_pass == new_pass:
                return False, "新密码不能与旧密码相同"

            cursor = self.connection.cursor()
            # 获取数据库中存储的明文密码
            query = "SELECT pass FROM cardInfo WHERE cardID = %s"
            cursor.execute(query, (card_id,))
            result = cursor.fetchone()

            if not result:
                return False, "银行卡号不存在"

            db_password = result[0]  # 数据库中存储的明文密码
            # 直接比较明文密码（不再进行哈希）
            if db_password != old_pass:
                return False, "原始密码错误"

            # 更新为新密码的明文（而不是哈希值）
            update_query = "UPDATE cardInfo SET pass = %s WHERE cardID = %s"
            cursor.execute(update_query, (new_pass, card_id))  # 直接存储明文
            self.connection.commit()

            return True, "密码修改成功"

        except Error as e:
            if self.connection:
                self.connection.rollback()
            return False, f"数据库错误: {str(e)}"
        finally:
            if cursor:
                cursor.close()
    def __del__(self):
        if hasattr(self, 'connection') and self.connection and self.connection.is_connected():
            self.connection.close()
            print("数据库连接已关闭")


class LoginWindow(QWidget):
    """登录窗口"""

    def __init__(self):
        super().__init__()
        self.bank_manager = None
        try:
            self.bank_manager = BankCardManager()
            self.init_ui()
        except Exception as e:
            QMessageBox.critical(self, "初始化错误", f"程序初始化失败: {str(e)}")
            raise

    def init_ui(self):
        """初始化用户界面"""
        self.setWindowTitle('银行卡登录')
        self.setFixedSize(1920, 1080)

        # 主布局
        main_layout = QVBoxLayout()
        main_layout.setAlignment(Qt.AlignCenter)
        main_layout.setSpacing(25)
        main_layout.setContentsMargins(40, 40, 40, 40)

        # 标题
        title_label = QLabel('银行卡登录系统')
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setStyleSheet('''
            font-size: 28px; 
            font-weight: bold;
            color: #2c3e50;
            margin-bottom: 30px;
        ''')
        main_layout.addWidget(title_label)

        # 登录表单组
        form_group = QGroupBox("登录信息")
        form_layout = QFormLayout()
        form_layout.setSpacing(15)

        # 卡号输入
        self.card_input = QLineEdit()
        self.card_input.setPlaceholderText("请输入16位银行卡号")
        self.card_input.setMaxLength(19)  # 16位数字+最多3个空格
        self.card_input.setStyleSheet('padding: 10px; font-size: 16px;')

        # 密码输入
        self.pwd_input = QLineEdit()
        self.pwd_input.setPlaceholderText("请输入6位密码")
        self.pwd_input.setMaxLength(6)
        self.pwd_input.setEchoMode(QLineEdit.Password)
        self.pwd_input.setStyleSheet('padding: 10px; font-size: 16px;')

        # 添加到表单
        form_layout.addRow("银行卡号:", self.card_input)
        form_layout.addRow("密    码:", self.pwd_input)
        form_group.setLayout(form_layout)

        # 登录按钮
        btn_login = QPushButton('登  录')
        btn_login.setFixedHeight(45)
        btn_login.setStyleSheet('''
            QPushButton {
                background-color: #3498db;
                color: white;
                border: none;
                border-radius: 5px;
                font-size: 18px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #2980b9;
            }
            QPushButton:pressed {
                background-color: #1d6fa5;
            }
        ''')
        btn_login.clicked.connect(self.on_login)

        # 添加到主布局
        main_layout.addWidget(form_group)
        main_layout.addWidget(btn_login)

        # 状态标签
        self.status_label = QLabel("就绪")
        self.status_label.setStyleSheet('font-size: 14px; color: #7f8c8d;')
        main_layout.addWidget(self.status_label, alignment=Qt.AlignCenter)

        self.setLayout(main_layout)

    def on_login(self):
        """处理登录逻辑"""
        card_id = self.card_input.text().strip()
        password = self.pwd_input.text().strip()

        # 清空状态信息
        self.status_label.setText("正在登录...")
        self.status_label.setStyleSheet('font-size: 14px; color: #f39c12;')
        QApplication.processEvents()  # 强制更新UI

        # 登录验证
        success, result = self.bank_manager.login(card_id, password)

        if success:
            user_info = result
            # 登录成功，打开主界面
            self.main_window = MainWindow(user_info, self.bank_manager)
            self.hide()
            self.main_window.show()
        else:
            error_message = result
            QMessageBox.warning(self, "登录失败", error_message)
            self.status_label.setText(f"错误: {error_message}")
            self.status_label.setStyleSheet('font-size: 14px; color: #e74c3c;')

    def closeEvent(self, event):
        """关闭窗口"""
        try:
            if hasattr(self, 'bank_manager') and self.bank_manager:
                self.bank_manager.__del__()
        except Exception as e:
            print(f"资源清理错误: {e}")
        event.accept()


class PasswordChangeDialog(QDialog):
    """密码修改对话框 - 完整修复版"""

    def __init__(self, card_id, bank_manager):
        """
        初始化密码修改对话框
        :param card_id: 银行卡号
        :param bank_manager: BankCardManager 实例
        """
        super().__init__()
        self.card_id = card_id
        self.bank_manager = bank_manager
        self.attempts = 0
        self.MAX_ATTEMPTS = 3
        self.init_ui()

    def init_ui(self):
        """初始化对话框界面"""
        self.setWindowTitle('修改密码')
        self.setFixedSize(800, 600)  # 调整为更合理的尺寸

        # 主布局
        main_layout = QVBoxLayout()
        main_layout.setSpacing(15)
        main_layout.setContentsMargins(20, 20, 20, 20)

        # 提示信息
        masked_card_id = f"{self.card_id[:4]} **** **** {self.card_id[-4:]}"
        info_label = QLabel(f"正在为卡号: {masked_card_id} 修改密码")
        info_label.setStyleSheet('font-size: 16px; font-weight: bold;')
        main_layout.addWidget(info_label, alignment=Qt.AlignCenter)

        # 表单组
        form_group = QGroupBox("密码信息")
        form_layout = QFormLayout()
        form_layout.setSpacing(10)

        # 密码输入字段
        self.old_pass = QLineEdit()
        self.old_pass.setPlaceholderText("请输入原密码")
        self.old_pass.setMaxLength(6)
        self.old_pass.setEchoMode(QLineEdit.Password)

        self.new_pass = QLineEdit()
        self.new_pass.setPlaceholderText("请输入新密码（6位数字）")
        self.new_pass.setMaxLength(6)
        self.new_pass.setEchoMode(QLineEdit.Password)

        self.confirm_pass = QLineEdit()
        self.confirm_pass.setPlaceholderText("请再次输入新密码")
        self.confirm_pass.setMaxLength(6)
        self.confirm_pass.setEchoMode(QLineEdit.Password)

        # 统一样式
        for input_field in [self.old_pass, self.new_pass, self.confirm_pass]:
            input_field.setStyleSheet('''
                QLineEdit {
                    padding: 8px;
                    font-size: 14px;
                    border: 1px solid #ddd;
                    border-radius: 4px;
                }
            ''')

        form_layout.addRow("原密码:", self.old_pass)
        form_layout.addRow("新密码:", self.new_pass)
        form_layout.addRow("确认密码:", self.confirm_pass)
        form_group.setLayout(form_layout)

        # 按钮布局
        btn_layout = QHBoxLayout()

        # 修改密码按钮
        btn_change = QPushButton('修改密码')
        btn_change.setFixedHeight(35)
        btn_change.setStyleSheet('''
            QPushButton {
                background-color: #27ae60;
                color: white;
                border: none;
                border-radius: 4px;
                font-size: 14px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #2ecc71;
            }
            QPushButton:pressed {
                background-color: #219653;
            }
        ''')
        btn_change.clicked.connect(self.on_change_password)

        # 取消按钮
        btn_cancel = QPushButton('取 消')
        btn_cancel.setFixedHeight(35)
        btn_cancel.setStyleSheet('''
            QPushButton {
                background-color: #95a5a6;
                color: white;
                border: none;
                border-radius: 4px;
                font-size: 14px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #bdc3c7;
            }
            QPushButton:pressed {
                background-color: #7f8c8d;
            }
        ''')
        btn_cancel.clicked.connect(self.reject)

        btn_layout.addWidget(btn_change)
        btn_layout.addWidget(btn_cancel)

        # 状态标签
        self.status_label = QLabel()
        self.status_label.setAlignment(Qt.AlignCenter)
        self.status_label.setStyleSheet('font-size: 13px;')

        # 添加到主布局
        main_layout.addWidget(form_group)
        main_layout.addLayout(btn_layout)
        main_layout.addWidget(self.status_label)

        self.setLayout(main_layout)

    def on_change_password(self):
        """处理密码修改逻辑 - 修复版"""
        # 检查尝试次数
        if self.attempts >= self.MAX_ATTEMPTS:
            self.status_label.setText("尝试次数过多，请稍后再试")
            self.status_label.setStyleSheet('color: #e74c3c;')
            return

        old_pass = self.old_pass.text()
        new_pass = self.new_pass.text()
        confirm_pass = self.confirm_pass.text()

        # 输入验证
        if not all([old_pass, new_pass, confirm_pass]):
            self.status_label.setText("请填写所有字段")
            self.status_label.setStyleSheet('color: #e74c3c;')
            return

        if new_pass != confirm_pass:
            self.attempts += 1
            remaining = self.MAX_ATTEMPTS - self.attempts
            self.status_label.setText(f"两次输入的新密码不一致 (剩余尝试次数: {remaining})")
            self.status_label.setStyleSheet('color: #e74c3c;')
            return

        # 修改密码
        self.status_label.setText("正在修改密码...")
        self.status_label.setStyleSheet('color: #f39c12;')
        QApplication.processEvents()  # 强制更新UI

        # 使用 BankCardManager 的 change_password 方法
        success, message = self.bank_manager.change_password(
            self.card_id, old_pass, new_pass
        )

        if success:
            QMessageBox.information(self, "成功", message)
            self.accept()
        else:
            self.attempts += 1
            remaining = self.MAX_ATTEMPTS - self.attempts
            if remaining > 0:
                self.status_label.setText(f"{message} (剩余尝试次数: {remaining})")
            else:
                self.status_label.setText("尝试次数过多，请稍后再试")
            self.status_label.setStyleSheet('color: #e74c3c;')


class MainWindow(QWidget):
    """主界面，允许用户修改密码"""

    def __init__(self, user_info, bank_manager):
        super().__init__()
        self.user_info = user_info
        self.bank_manager = bank_manager
        self.init_ui()

    def init_ui(self):
        """初始化主界面"""
        self.setWindowTitle('银行卡服务')
        self.setFixedSize(1920, 1080)

        # 主布局
        main_layout = QVBoxLayout()
        main_layout.setAlignment(Qt.AlignCenter)
        main_layout.setSpacing(25)
        main_layout.setContentsMargins(40, 40, 40, 40)

        # 欢迎标题
        card_id = self.user_info['cardID']
        title_label = QLabel(f'欢迎, {card_id[:4]} **** **** {card_id[-4:]}')
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setStyleSheet('''
            font-size: 24px; 
            font-weight: bold;
            color: #2c3e50;
        ''')
        main_layout.addWidget(title_label)

        # 账户信息组
        info_group = QGroupBox("账户信息")
        info_layout = QFormLayout()
        info_layout.setSpacing(15)

        # 账户信息显示
        customer_id = QLabel(str(self.user_info['customerID']))
        balance = QLabel(f"¥ {self.user_info['balance']:.2f}")
        status = QLabel("正常" if self.user_info['IsReportLoss'] == '否' else "已挂失")

        # 添加到表单
        info_layout.addRow("卡号:", QLabel(self.user_info['cardID']))
        info_layout.addRow("客户ID:", customer_id)
        info_layout.addRow("当前余额:", balance)
        info_layout.addRow("状态:", status)
        info_group.setLayout(info_layout)

        # 功能按钮
        btn_change_password = QPushButton('修改密码')
        btn_change_password.setFixedHeight(45)
        btn_change_password.setStyleSheet('''
            QPushButton {
                background-color: #3498db;
                color: white;
                border: none;
                border-radius: 5px;
                font-size: 18px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #2980b9;
            }
            QPushButton:pressed {
                background-color: #1d6fa5;
            }
        ''')
        btn_change_password.clicked.connect(self.show_password_change_dialog)

        # 退出按钮
        btn_logout = QPushButton('退  出')
        btn_logout.setFixedHeight(45)
        btn_logout.setStyleSheet('''
            QPushButton {
                background-color: #e74c3c;
                color: white;
                border: none;
                border-radius: 5px;
                font-size: 18px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #c0392b;
            }
            QPushButton:pressed {
                background-color: #a93226;
            }
        ''')
        btn_logout.clicked.connect(self.logout)

        # 添加到主布局
        main_layout.addWidget(info_group)
        main_layout.addWidget(btn_change_password)
        main_layout.addWidget(btn_logout)

        self.setLayout(main_layout)

    def show_password_change_dialog(self):
        """显示密码修改对话框"""
        dialog = PasswordChangeDialog(self.user_info['cardID'], self.bank_manager)
        dialog.exec_()

    def logout(self):
        """退出登录"""
        self.close()
        login_window = LoginWindow()
        login_window.show()

    def closeEvent(self, event):
        """关闭窗口"""
        event.accept()


if __name__ == '__main__':
    try:
        app = QApplication(sys.argv)
        font = QFont("Microsoft YaHei" if sys.platform == 'win32' else "Arial", 14)
        app.setFont(font)

        window = LoginWindow()
        window.show()
        sys.exit(app.exec_())
    except Exception as e:
        QMessageBox.critical(None, "错误", f"程序启动失败: {str(e)}")